package com.skivingcloud.camunda.controller;

import com.mybatisflex.core.paginate.Page;
import com.skivingcloud.admin.logutils.OperateLog;
import com.skivingcloud.admin.security.SecurityUser;
import com.skivingcloud.admin.utils.UserUtil;
import com.skivingcloud.camunda.constants.WorkflowConstants;
import com.skivingcloud.camunda.entity.ProcessVo;
import com.skivingcloud.camunda.entity.TaskVo;
import com.skivingcloud.camunda.service.LovelyProcessService;
import com.skivingcloud.common.exceptions.BusinessException;
import com.skivingcloud.common.utils.PageParameter;
import com.skivingcloud.common.utils.ReturnT;
import com.skivingcloud.workflow.api.entity.TaskParam;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import java.text.ParseException;
import java.util.List;
import java.util.Map;

/**
 * @author hushouquan
 * @since 2024/3/13
 */
@RestController
@Tag(name = "流程管理")
@RequestMapping(WorkflowConstants.WORKFLOW_BASE_URL + "/process")
public class ProcessController{
    private static final Logger log = LoggerFactory.getLogger(ProcessController.class);
    
    @Resource
    private LovelyProcessService lovelyProcessService;
    
    /**
     * 流程提交方法
     * @param taskParam 参数
     * @return 结果
     */
    @OperateLog(module="流程管理", description = "流程提交")
    @PostMapping("/submitTask")
    @Operation(summary="流程提交")
    public ReturnT<String> submitTask(@RequestBody TaskParam taskParam){
        try{
            if(taskParam.getUserId() == null){
                taskParam.setUserId(UserUtil.getCurrentUser().getId());
            }
            String processInstanceId = lovelyProcessService.submitTask(taskParam);
            return ReturnT.ok(processInstanceId);
        }catch(IllegalArgumentException | BusinessException ie){
            log.error(ie.getMessage(), ie);
            return ReturnT.error(ie.getMessage());
        }catch(Exception e){
            log.error(e.getMessage(), e);
            return ReturnT.error("提交流程失败");
        }
    }
    
    /**
     * 查询待办任务
     * @param parameter 参数
     * @return 结果
     */
    @PostMapping("/todoList")
    @Operation(summary="查询待办任务")
    public ReturnT<Page<TaskVo>> todoList(@RequestBody @Parameter(description="分页信息") PageParameter<Map<String, Object>> parameter){
        try{
            SecurityUser user = UserUtil.getCurrentUser();
            if(user==null){
                throw new BusinessException("当前用户不合法");
            }
            Page<TaskVo> taskList = lovelyProcessService.getTodoListByPage(parameter, user.getId());
            return ReturnT.ok(taskList);
        }catch(IllegalArgumentException | BusinessException ie){
            log.error(ie.getMessage(), ie);
            return ReturnT.error(ie.getMessage());
        }catch(Exception e){
            log.error(e.getMessage(), e);
            return ReturnT.error("待办任务查询失败");
        }
    }
    
    /**
     * 分页查询我发起的流程
     * @param parameter 参数
     * @return 流程
     */
    @PostMapping("/createList")
    @Operation(summary="分页查询我发起的流程")
    public ReturnT<Page<ProcessVo>> createList(@RequestBody @Parameter(description="分页信息") PageParameter<Map<String, Object>> parameter){
        try{
            SecurityUser user = UserUtil.getCurrentUser();
            if(user == null){
                throw new BusinessException("当前用户不合法");
            }
            Page<ProcessVo> processList = lovelyProcessService.getCreateListByPage(parameter, user.getId());
            return ReturnT.ok(processList);
        }catch(IllegalArgumentException | BusinessException ie){
            log.error(ie.getMessage(), ie);
            return ReturnT.error(ie.getMessage());
        }catch(Exception e){
            log.error(e.getMessage(), e);
            return ReturnT.error("我发起的流程查询失败");
        }
    }
    
    /**
     * 分页查询我参与的流程
     * @param parameter 参数
     * @return 流程
     */
    @PostMapping("/partakeList")
    @Operation(summary="分页查询我参与的流程")
    public ReturnT<Page<ProcessVo>> partakeList(@RequestBody @Parameter(description="分页信息") PageParameter<Map<String, Object>> parameter){
        try{
            SecurityUser user = UserUtil.getCurrentUser();
            Page<ProcessVo> processList = lovelyProcessService.getPartakeListByPage(parameter, user);
            return ReturnT.ok(processList);
        }catch(IllegalArgumentException | BusinessException ie){
            log.error(ie.getMessage(), ie);
            return ReturnT.error(ie.getMessage());
        }catch(Exception e){
            log.error(e.getMessage(), e);
            return ReturnT.error("我参与的流程查询失败");
        }
    }
    
    /**
     * 根据id查询流程审批历史记录
     * @param processId 流程实例ID
     * @return 审批记录
     */
    @GetMapping("/getHisTaskByProcessId/{processId}")
    @Operation(summary="根据id查询流程审批历史记录")
    public ReturnT<List<TaskVo>> getHisTaskByProcessId(@PathVariable("processId") String processId){
        return ReturnT.ok(lovelyProcessService.getHisTaskByProcessId(processId));
    }
    
    /**
     * 根据任务id查询可退回节点
     * @param taskId 任务ID
     * @return 可退回节点
     */
    @GetMapping("/getRetractNodeByTaskId/{taskId}")
    @Operation(summary="根据任务id查询可退回节点")
    public ReturnT<List<TaskVo>> getRetractNodeByTaskId(@PathVariable("taskId") String taskId){
        return ReturnT.ok(lovelyProcessService.getRetractNodeByTaskId(taskId));
    }
    
    /**
     * 终止流程
     * @param params 流程参数
     * @return 终止结果
     */
    @OperateLog(module="流程管理", description = "终止流程")
    @PostMapping("/deleteProcess")
    @Operation(summary="终止流程")
    public ReturnT<String> deleteProcess(@RequestBody Map<String, Object> params){
        try{
            lovelyProcessService.deleteProcess(params);
            return ReturnT.ok("终止流程成功");
        }catch(BusinessException be){
            return ReturnT.error(be.getMessage());
        }catch(Exception e){
            log.error("终止流程失败", e);
            return ReturnT.error("终止流程失败");
        }
    }
    
    /**
     * 根据流程实例id获取流程文件xml及高亮
     * @param id 流程实例id
     * @return 流程文件xml
     */
    @GetMapping("/getResourceAndStateByProcessId/{id}")
    @Operation(summary="根据流程实例id获取流程文件xml")
    public ReturnT<Map<String, Object>> getResourceAndStateByProcessId(@PathVariable(name="id") String id){
        try{
            Map<String, Object> processInfo = lovelyProcessService.getResourceAndStateByProcessId(id);
            return ReturnT.ok(processInfo);
        }catch(Exception e){
            log.error("获取流程文件内容失败", e);
            return ReturnT.error("获取流程文件内容失败");
        }
    }
    
    /**
     * 检入检出流程任务（检出/放弃处理）
     * @param taskId 任务ID
     * @param sign 检入/检出 WorkflowConstants.TaskSign
     * @return 执行结果
     */
    @OperateLog(module="流程管理", description = "检入检出流程任务")
    @GetMapping("/doClaimTask/{taskId}/{sign}")
    @Operation(summary="检入检出流程任务")
    public ReturnT<Map<String, Object>> doClaimTask(@PathVariable("taskId") String taskId, @PathVariable("sign") String sign){
        try{
            lovelyProcessService.doClaimTask(taskId, sign, UserUtil.getCurrentUser().getId());
            return ReturnT.ok();
        }catch(Exception e){
            log.error("检入检出流程任务失败", e);
            return ReturnT.error("检入检出流程任务失败");
        }
    }
    /**
     * 挂起或恢复流程
     * @param processId 流程实例ID
     * @param state 状态
     * @return 处理结果
     */
    @OperateLog(module="流程管理", description = "挂起或恢复流程")
    @GetMapping("/suspendOrActiveProcess/{processId}/{state}")
    @Operation(summary="挂起或恢复流程")
    public ReturnT<String> suspendOrActiveProcess(@PathVariable("processId") String processId,
                                                  @PathVariable("state") String state){
        try{
            lovelyProcessService.suspendOrActiveProcess(processId, state);
            return ReturnT.ok();
        }catch(Exception e){
            log.error("挂起或恢复流程失败", e);
            return ReturnT.error("挂起或恢复流程失败");
        }
    }
    
    /**
     * 发起人撤回流程
     * @param processId 流程实例ID
     * @return 处理结果
     */
    @OperateLog(module="流程管理", description = "发起人撤回流程")
    @GetMapping("/recallTaskByStarter/{processId}")
    @Operation(summary="发起人撤回流程")
    public ReturnT<String> recallTaskByStarter(@PathVariable("processId") String processId){
        try{
            lovelyProcessService.recallTaskByStarter(processId);
            return ReturnT.ok();
        }catch(Exception e){
            log.error("发起人撤回流程失败", e);
            return ReturnT.error("发起人撤回流程失败");
        }
    }
    
    /**
     * 获取可撤回节点
     * @param processId 流程实例ID
     * @return 可撤回节点
     */
    @GetMapping("/getCanRecallTask/{processId}")
    @Operation(summary="获取可撤回节点")
    public ReturnT<List<TaskVo>> getCanRecallTask(@PathVariable("processId") String processId){
        try{
            return ReturnT.ok(lovelyProcessService.getCanRecallTask(processId, UserUtil.getCurrentUser().getId()));
        }catch(Exception e){
            log.error("获取获取可撤回节点失败", e);
            return ReturnT.error("获取获取可撤回节点失败");
        }
    }
    
    /**
     * 任意撤回流程，选择一个节点撤回
     * @param params 参数
     * @return 撤回结果
     */
    @OperateLog(module="流程管理", description = "撤回流程")
    @PostMapping("/recallTaskAny")
    @Operation(summary="撤回流程")
    public ReturnT<String> recallTaskAny(@RequestBody Map<String, Object> params){
        try{
            lovelyProcessService.recallTaskAny(params, UserUtil.getCurrentUser().getId());
            return ReturnT.ok("撤回流程成功");
        }catch(BusinessException be){
            return ReturnT.error(be.getMessage());
        }catch(Exception e){
            log.error("撤回流程失败", e);
            return ReturnT.error("撤回流程失败");
        }
    }
    
    /**
     * 驳回流程
     * @param params 参数
     * @return 结果
     */
    @OperateLog(module="流程管理", description = "驳回流程")
    @PostMapping("/submitRetract")
    @Operation(summary="驳回流程")
    public ReturnT<String> submitRetract(@RequestBody Map<String, Object> params){
        try{
            lovelyProcessService.submitRetract(params, UserUtil.getCurrentUser().getId());
            return ReturnT.ok("驳回流程成功");
        }catch(BusinessException be){
            return ReturnT.error(be.getMessage());
        }catch(Exception e){
            log.error("驳回流程失败", e);
            return ReturnT.error("驳回流程失败");
        }
    }
    
    /**
     * 流程管理分页查询
     * @param parameter 查询参数
     * @return 分页结果
     */
    @PostMapping("/queryProcessPage")
    @Operation(summary="流程管理查询")
    public ReturnT<Page<ProcessVo>> queryProcessPage(@RequestBody PageParameter<ProcessVo> parameter){
        try{
            Page<ProcessVo> page = lovelyProcessService.queryProcessPage(parameter);
            return ReturnT.ok(page);
        }catch(ParseException e){
            log.error("日期转换异常", e);
            return ReturnT.ok();
        }
    }
    
    /**
     * 流程转办
     * @param taskId 流程任务ID
     * @param userId 用户ID
     * @return 处理结果
     */
    @OperateLog(module="流程管理", description = "流程转办")
    @GetMapping("/transferProcess/{taskId}/{userId}")
    @Operation(summary="流程转办")
    public ReturnT<String> transferProcess(@PathVariable("taskId") String taskId, @PathVariable("userId") String userId){
        try{
            if(StringUtils.isBlank(taskId)){
                return ReturnT.error("请选择要转办的流程任务");
            }
            if(StringUtils.isBlank(userId)){
                return ReturnT.error("请选择要流程要转给的人员");
            }
            if(taskId.split(",").length > 1){
                return ReturnT.error("多人会签任务不允许转办");
            }
            lovelyProcessService.transferProcess(taskId, userId);
            return ReturnT.ok();
        }catch(Exception e){
            log.error("流程转办失败", e);
            return ReturnT.error("流程转办失败");
        }
    }
}
